package com.example.tool.subject;

import com.example.tool.action.ConfigActions;
import com.example.tool.module.ModulePInformation;
import com.example.tool.utils.AES;
import com.example.tool.utils.FileUtil;
import com.example.tool.utils.WebServersUtil;
import com.intellij.execution.RunManager;
import com.intellij.execution.RunnerAndConfigurationSettings;
import com.intellij.execution.configurations.RunConfiguration;
import com.intellij.execution.remote.RemoteConfiguration;
import com.intellij.execution.remote.RemoteConfigurationType;
import com.intellij.ide.util.projectWizard.JavaModuleBuilder;
import com.intellij.ide.util.projectWizard.ModuleWizardStep;
import com.intellij.ide.util.projectWizard.ProjectWizardStepFactory;
import com.intellij.ide.util.projectWizard.SettingsStep;
import com.intellij.ide.util.projectWizard.WizardContext;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.JavaModuleType;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.module.ModuleType;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.CompilerModuleExtension;
import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.roots.ModuleRootModificationUtil;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.libraries.LibraryTable;
import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * <p>Title: SubjectModuleBuilder</p >
 * Description: 自定义模块构建
 * <p>CreateTime: 2022/6/21 9:11</p>
 * @author FT
 */
public class HToolModuleBuilder extends JavaModuleBuilder {
  private static final Logger LOG = Logger.getInstance(HToolModuleBuilder.class);
  private static HToolModuleWizardStep hToolModuleWizardStep;
  private static HToolModuleBuilder htoolModuleBuilder;

  private HToolModuleBuilder() {
  }

  @Override
  public boolean isAvailable() {
    return true;
  }

  public static HToolModuleBuilder getInstance() {
    if (htoolModuleBuilder == null) {
      htoolModuleBuilder = new HToolModuleBuilder();
    }
    return htoolModuleBuilder;
  }

  @Override
  public ModuleType<?> getModuleType() {
    return new HToolModuleType();
  }

  @Override
  public int getWeight() {
    return ModulePInformation.MODULE_WEIGHT;
  }

  @Override
  public String getParentGroup() {
    return JavaModuleType.JAVA_GROUP;
  }

  @Override
  public void setupRootModel(@NotNull ModifiableRootModel model) {
    try {
      LOG.info("SeeyonTool Build project start");
      String basePath = model.getProject().getBasePath();
      createFile(basePath);
      super.setupRootModel(model);
      compilePath(model);
      runConfigurable(model);
      LOG.info("SeeyonTool Build project end");
    } catch (ConfigurationException e) {
      e.printStackTrace();
    }
  }

  @Nullable
  @Override
  public ModuleWizardStep getCustomOptionsStep(WizardContext context, Disposable parentDisposable) {
    hToolModuleWizardStep = HToolModuleWizardStep.getInstance();
    return hToolModuleWizardStep;
  }

  @Override
  public ModuleWizardStep modifySettingsStep(@NotNull SettingsStep settingsStep) {
    return ProjectWizardStepFactory.getInstance().createJavaSettingsStep(settingsStep, htoolModuleBuilder, htoolModuleBuilder::isSuitableSdkType);
  }

  private void addLibrary(ModifiableRootModel model, String pathJar, String pluginID) {
    // 调用写线程
    Application application = ApplicationManager.getApplication();
    application.invokeLater(() -> application.runWriteAction(() -> {
      final List<Pair<String, String>> pairList = new ArrayList<>();
      FileUtil.getAllJar(pathJar, value -> pairList.add(Pair.create(value, null)));
      LibraryTable libraryTable = LibraryTablesRegistrar.getInstance().getLibraryTable(model.getProject());
      Library library = libraryTable.createLibrary(pluginID);

      for (Pair<String, String> libInfo : pairList) {
        final String moduleLibraryPath = libInfo.first;
        final String sourceLibraryPath = libInfo.second;
        Library.ModifiableModel modifiableModel = library.getModifiableModel();
        modifiableModel.addRoot(VfsUtil.getUrlForLibraryRoot(new File(moduleLibraryPath)), OrderRootType.CLASSES);
        if (sourceLibraryPath != null) {
          modifiableModel.addRoot(VfsUtil.getUrlForLibraryRoot(new File(sourceLibraryPath)), OrderRootType.SOURCES);
        }
        modifiableModel.commit();
      }
      if (pairList.size() > 0) {
        ModuleRootModificationUtil.addDependency(model.getModule(), library);
      }
    }));
  }

  // 设置项目的远程配置文件
  private void runConfigurable(ModifiableRootModel model) {
    Project project = model.getProject();
    ApplicationManager.getApplication().invokeLater(() -> {
      // StartupManager.getInstance(project).runAfterOpened(() -> {
      String text = hToolModuleWizardStep.getTextFieldWithBrowseButton().getText();
      String pluginId = hToolModuleWizardStep.getPluginID().getText();
      String pluginStaticDirectory = hToolModuleWizardStep.getStaticDirectory().getText();
      Module[] modules = ModuleManager.getInstance(project).getModules();
      if (modules.length < 1) return;
      RunManager runManager = RunManager.getInstance(project);
      RemoteConfigurationType instance = RemoteConfigurationType.getInstance();
      RunnerAndConfigurationSettings runnerAndConfigurationSettings = runManager.createConfiguration("RunDeBug", instance);
      RunConfiguration configuration = runnerAndConfigurationSettings.getConfiguration();
      if (!(configuration instanceof RemoteConfiguration)) return;
      ((RemoteConfiguration) configuration).setModule(modules[0]);
      ((RemoteConfiguration) configuration).PORT = hToolModuleWizardStep.getRemotePort().getText();
      runManager.addConfiguration(runnerAndConfigurationSettings);
      runManager.setSelectedConfiguration(runnerAndConfigurationSettings);

      // deployment.xml
      FileUtil.generateFile(project.getBasePath() + "/.idea/deployment.xml", "/.idea/deployment.xml", str -> str.replace("$pluginCategory$", "STOOL"));
      ConfigActions.UpdateDeployment(project, pluginStaticDirectory, LOG);

      String uuid = UUID.randomUUID().toString();
      // webServers.xml
      FileUtil.generateFile(project.getBasePath() + "/.idea/webServers.xml", "/.idea/webServers.xml", str -> WebServersUtil.changeConfiguration(str, text, uuid));

      // Seeyon.txt
      String txt = text + "|" + pluginId + "|" + pluginStaticDirectory + "|" + uuid;
      FileUtil.generateFile(project.getBasePath() + "/.idea/" + ModulePInformation.MODULE_CONFIG, AES.encryption(ModulePInformation.MODULE_SECRET_KEY, txt));

      // 刷新文件视图
      LocalFileSystem.getInstance().refresh(true);
      TextFieldWithBrowseButton textFieldWithBrowseButton = hToolModuleWizardStep.getTextFieldWithBrowseButton();
      addLibrary(model, textFieldWithBrowseButton.getText(), pluginId);
      // 清除设置的值
      hToolModuleWizardStep.clear();
    });
  }


  private void createFile(String projectPath) {
    String pluginId = hToolModuleWizardStep.getPluginID().getText();
    String pluginName = hToolModuleWizardStep.getPluginName().getText();
    String pluginCategory = hToolModuleWizardStep.getPluginCategory().getText();
    String pluginStaticDirectory = hToolModuleWizardStep.getStaticDirectory().getText();
    List<Pair<String, String>> sourcePaths = new ArrayList<>();
    // 源码路径
    String path = projectPath + "/src";
    FileUtil.createFilePath(path);
    sourcePaths.add(Pair.create(path, ""));

    // 插件包路径
    String pathBase = path + "_" + pluginId;
    sourcePaths.add(Pair.create(pathBase, ""));
    super.setSourcePaths(sourcePaths);

    // 代码路径
    String initClass = pathBase + "/com/seeyon/apps/" + pluginId;
    FileUtil.createFilePath(initClass);

    // META-INF路径
    String METAPath = projectPath + "/" + pluginStaticDirectory + "/META-INF";
    FileUtil.createFilePath(METAPath);

    // 插件路径
    String pluginPathBase = projectPath + "/" + pluginStaticDirectory + "/WEB-INF/cfgHome/plugin/" + pluginId;
    String pluginPath = pluginPathBase + "/spring";
    FileUtil.createFilePath(pluginPath);

    // PluginInitializer.java
    String $ClassName$ = FileUtil.upperFirstCase(pluginId) + "PluginInitializer";
    FileUtil.generateFile(initClass + "/" + $ClassName$ + ".java", "/demo/init/DemoPluginInitializer.txt", str -> str.replace("$PluginPackage$", pluginId).replace("$ClassName$", $ClassName$).replace("$TIME$", new SimpleDateFormat("yyyy-MM-dd").format(new Date())).replace("$PluginName$", pluginName));

    // MANIFEST.MF
    FileUtil.generateFile(METAPath + "/MANIFEST.MF", "Manifest-Version: 1.0\n");

    // pluginCfg.xml
    FileUtil.generateFile(pluginPathBase + "/pluginCfg.xml", "/demo/pluginCfg.txt", str -> str.replace("$pluginId$", pluginId).replace("$pluginName$", pluginName).replace("$pluginCategory$", pluginCategory));

    // pluginProperties.xml
    FileUtil.generateFile(pluginPathBase + "/pluginProperties.xml", "/demo/pluginProperties.txt", str -> str.replace("$pluginId$", pluginId).replace("$pluginName$", pluginName));

    // spring-XX-plugin.xml
    FileUtil.generateFile(pluginPath + "/spring-" + pluginId + "-plugin.xml", "/demo/spring/spring-demo-plugin.txt", str -> str.replace("$ClassName$", FileUtil.lowerFirstCase($ClassName$)).replace("$ClassPath$", "com.seeyon.apps." + pluginId + "." + $ClassName$));

    // 刷新文件视图
    LocalFileSystem.getInstance().refresh(true);
  }

  private void compilePath(ModifiableRootModel model) {
    CompilerModuleExtension instance = model.getModuleExtension(CompilerModuleExtension.class);
    instance.inheritCompilerOutputPath(false);
    instance.setExcludeOutput(true);
    String compilerOutputPath = VfsUtilCore.pathToUrl(model.getProject().getBasePath() + "/" + hToolModuleWizardStep.getStaticDirectory().getText() + "/WEB-INF/classes");
    String canonicalPath;
    try {
      canonicalPath = com.intellij.openapi.util.io.FileUtil.resolveShortWindowsName(compilerOutputPath);
    } catch (IOException e) {
      canonicalPath = compilerOutputPath;
    }
    instance.setCompilerOutputPath(canonicalPath);
  }
}
